Part I: R
Introduction
What is
R?
R is a programming language used for
statistical analysis and graphics. It is based on S-plus, which itself
was based on S, a programming language originally developed by
AT&T.
Why
R?
- Open source, cross-platform, and free
- Great for reproducibility
- Interdisciplinary and extensible
- Tons of learning resources
- Works on data of all shapes and sizes
- Produces high-quality graphics
- Large and welcoming community
R:
Object-Oriented Programming
Unlike many other statistical software such as SAS and SPSS,
R will not spit out a mountain of output on the screen.
Instead, R returns an object containing
all the results. You, as an user, have the flexibility to choose which
result to be extracted or reported.
R:
Functional Programming
This feature allows us to write faster yet more compact code. For
example, a common theme in R programming is
avoidance of explicit iteration. Unlike many other
statistical softwares, explicit loops are discouraged.
Instead, R provides some functions that could allow us
to express iterative behavior implicitly.
R:
Polymorphic
R is also polymorphic, which means that a
single function can be applied to different types of inputs (much more
user friendly).
Such a function is called a generic function (If you are a
C++ programmer, you have seen a similar concept in virtual
functions).
Polymorphic -
Example
Lets look at one example plot()
- Plot a vector of numbers
- Plot some model results
No matter which purpose, we use the same function.
dats <- c(1,2,3,4)
plot(dats)

# Regression Analysis
par(mfrow=c(2,2),mar=c(2,4,2,2))
results <- lm(speed ~ dist,data=cars)
plot(results)

Why R Studio?
R Interface is ugly!
Many students in this class are much more familiar with Windows
operation system and have never been exposed programming before, so we
will use R studio, one of the free Graphical User Interfaces (GUIs) that
have been developed for R.
R studio should really be considered as integrated
development environments (IDEs), since it is aimed more toward
programming.
Easy publishing of reproducible documents such as reports,
interactive visualizations, presentations, and websites.
R Studio: A short
tour
Initial Start
When you first (like very first time) open R studio you will see
three panels.

Console

- Every time you launch RStudio, it will have the same text at the top
of the console telling you the version of R that you’re running.
- Below that information is the prompt,
> . As its
name suggests, this prompt is really a request, a request for a
command.
- Initially, interacting with R is all about typing commands and
interpreting the output.
- These commands and their syntax have evolved over decades
(literally) and now provide what many users feel is a fairly natural way
to access data and organize, describe, and invoke statistical
computations.
The console is where you type commands and have them immediately
performed.
Environment
The panel in the upper right contains your workspace (aka
Environment)

- This shows you a list of objects/variables that R has saved.
- For example here a value of
3 has been assigned to the
object a.
History
Up here there is an additional tab to see the history of the commands
that you’ve previously entered.

Files
The files tab allows you to open code/script files within R
studio.

Plots
Any plots that you generate will show up in the panel in the lower
right corner.

Help
To check the syntax of any function in R, type ? in front of the
function name to pull up the help file.

For example here I typed ?mean to get the help file for
the mean function. The help files are not always the most useful but are
usually a good place to start.
Script File The top left is your editor window,
where you write code or script, the console is now at the bottom.
I usually change it

The picture above illustrates my preferred style in R Studio.
R Script
Most of R users typically submit commands to
R by typing either in console or editor panel, rather than
clicking a mouse in a Graphical User Interface (GUI).
In class, we will make extensive use of scripts. A
Script is nothing but a collection of commands
and procedures that the coder performed to get to their results and
conclusions..
There are at least two advantages of doing so:
- As explained earlier, this allows us to run a bunch of results
altogether by putting a collection of commands in a file.
- It is also a lot more transparent and straightforward to
share and replicate what you have
done.
This will always be our approach in this class!!!
RMarkdown
Your assignments will use a slightly different approach as you will
be required to produce a .pdf file via an .Rmd
file. Think of this as an interactive version of the R Script. Here, we
are able to embed our codes and results with little effort. RMarkdown is
focused on reproducibility and less on the static codes presented in
your R scripts.
The next lesson covers RMarkdown files and its flexibility.
Exercise
Task
1: Create a script file
- Open R Studio and go to
File > New > R Script.
This will open a blank text document.
- Two alternative ways are:
- CTRL + SHIFT + N or
- press the button marked “+”, just below File, and select R
Script
- In the document, type
x = 5 # Assign the variable x a value of 5
x == 5 # Does x = 5? Notice the double ==
Highlight both lines of code and click the button marked “Run”.
If everything is working correctly, the console should display
TRUE.
OR, pressing CTRL + ENTER or COMMAND +
RETURN depending on whether you’re running Mac OSX, Linux or
Windows.
- Go to “File > Save As”, and choose a file name.
Part III:
R Data types
Data types in
R
You have observed a few of the different data types in the earlier
sections. Here, we will formally discuss them. Some of the most basic
data types we will cover are:
- Decimal values like 4.5 are called numerics.
- Natural numbers like 4 are called integers.
Integers are also numerics.
- Boolean values (TRUE or FALSE) are also called
logical.
- Text (or string) values are called characters.
You can check the type of data by using class().
x <- "Lyrics to Virginia Tech Fight Song!"
class(x)
[1] "character"
x2 <- c("TRUE", "FALSE")
x2 <- as.logical(x2) #Declare the data type
x2
[1] TRUE FALSE
[1] "logical"
x <- 1:20
x %% 4 #x mod 4
[1] 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0
[1] FALSE FALSE FALSE TRUE FALSE FALSE FALSE TRUE FALSE FALSE FALSE
[12] TRUE FALSE FALSE FALSE TRUE FALSE FALSE FALSE TRUE
[1] "logical"
Vectors
A vector is the most common and basic data type in R, and is pretty
much the workhorse of R. A vector is characterized by a series of
values, which can be either numbers or characters. We can assign a
series of values to a vector using the c() function.
In short, vectors are most useful when we have a collection of data
points.
Here c() stands for concatenate or
combine.
[1] 1 2 3 4
[1] 1 2 3 4
(v <- seq(from = 0, to = 0.5, by = 0.1))
[1] 0.0 0.1 0.2 0.3 0.4 0.5
#A vector can also contain characters:
(v_colors <- c("blue", "yellow", "light green") )
[1] "blue" "yellow" "light green"
Notice that by encasing the beginning and end of the assignment
lines in parentheses, we immediately print the stored values.
Subsetting vectors
(Indexing/reassigning elements)
We are able to index (collect subsets of our variables) by using
squared brackets. Unlike python, for example, R’s indexing begins from
1.
v_colors[2] # We are trying to extract the second element of the vector, v_colors
[1] "yellow"
v_colors[c(1,3)] # We can use the concatenation function to get nonconsecutive elements. Here, we are trying to extract elements in positions 1 and 3.
[1] "blue" "light green"
How would your extract elements 1:9, 15, 19, 20 and 21:30 in
zz below?
set.seed(1234)
zz <- rnorm(100)
Answer:
zz[c(1:19,15, 19, 20:30)]
[1] -1.20706575 0.27742924 1.08444118 -2.34569770 0.42912469
[6] 0.50605589 -0.57473996 -0.54663186 -0.56445200 -0.89003783
[11] -0.47719270 -0.99838644 -0.77625389 0.06445882 0.95949406
[16] -0.11028549 -0.51100951 -0.91119542 -0.83717168 0.95949406
[21] -0.83717168 2.41583518 0.13408822 -0.49068590 -0.44054787
[26] 0.45958944 -0.69372025 -1.44820491 0.57475572 -1.02365572
[31] -0.01513830 -0.93594860
We can replace elements in specific positions. Below, we replace the
second and third colors with red and
purple.
(v_colors[2:3] <- c("red", "purple") )
[1] "red" "purple"
Sometimes it might be more convenient to get rid of particular
elements instead. For example, I might want to extract all
but the first 5 elements of a vector, or all but the
15th element. We might find it easier to use a negative index here.
[1] 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
# We could have done that in one go as well
x[-c(1:3)]
[1] 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Conditional
subsetting
Another common way to subset is by using a logical vector.
TRUE will select the element with the same index, while
FALSE will not. Typically, these logical vectors are not
typed by hand, but are the output of other functions or logical tests
such as:
[1] 100 101 102 103 104 105 106 107 108 109 110
x >105 # returns TRUE or FALSE depending on which elements that meet the condition
[1] FALSE FALSE FALSE FALSE FALSE FALSE TRUE TRUE TRUE TRUE TRUE
select <- x > 105
x[select]
[1] 106 107 108 109 110
If we would like the elements that evaluate to FALSE
instead, we could easily use the ! (NOT)
operator
[1] 100 101 102 103 104 105
You can combine multiple tests using:
We can test whether x is between the range 103 and 106:
[1] 103 104 105 106
x is greater than 103 but (AND) less than or equal to
106
x[x <= 106 & x > 103] # order of subsetting does not matter here!
[1] 104 105 106
x is less than 103 or greater than 106
[1] 100 101 102 106 107 108 109 110
Sometimes we will need to search for certain strings in a vector.
With multiple conditions, it becomes difficult to use the “OR” operator
|. The function %in% allows you to test if any
of the elements of a search vector are found:
animals <- c("mouse", "rat", "dog", "cat")
animals[animals == "cat" | animals == "rat"] # returns both rat and cat
[1] "rat" "cat"
animals %in% c("rat", "cat", "dog", "duck", "goat")
[1] FALSE TRUE TRUE TRUE
animals[animals %in% c("rat", "cat", "dog", "duck", "goat")]
[1] "rat" "dog" "cat"
Names of a
vector
Let’s say that we want to know which color robe each of 3 patients is
wearing, we can assign names to the vector of colors.
[1] "blue" "red" "purple"
names(v_colors) <- c("Thomas", "Liz", "Tucker")
v_colors
Thomas Liz Tucker
"blue" "red" "purple"
Algebraic Operations
of Vectors
x <- c(1,2,3)
y <- c(4,5,6)
# component-wise addition
x+y
[1] 5 7 9
# component-wise multiplication
x*y
[1] 4 10 18
# What happens to the following
y^x # or y**x
[1] 4 25 216
Repeating Vector in
R
# Would this work?
c(1,2,3,4) + c(1,2)
[1] 2 4 4 6
# Would this work?
c(1,2,3) + c(1,2)
Warning: longer object length is not a multiple of shorter object length
[1] 2 4 4
Why the weird results?
- When you are adding vectors of unequal size, if the long one is a
multiple of the short one,
R automatically repeats the
short one to fill in the operation.
[1] 2 4 6
Matrix
Create a new matrix
(matrix<-matrix(1:16, nrow = 4, byrow = TRUE))
[,1] [,2] [,3] [,4]
[1,] 1 2 3 4
[2,] 5 6 7 8
[3,] 9 10 11 12
[4,] 13 14 15 16
Note that : means every number from 1 to 4. In the
matrix() function:
- The first argument is the collection of elements that
R
will arrange into the rows and columns of the matrix. Here, we use 1:16
which is a shortcut for c(1, 2, 3, 4, … 16).
- The argument
byrow indicates that the matrix is filled
by the rows. If we want the matrix to be filled by the columns, we use
byrow = FALSE.
- The argument
nrow indicates that the matrix should have
4 rows.
Selection of Matrix
Elements
Selection of the matrix elements are similar to vectors except we
have two dimensions over which to subset- rows and columns.
# matrix[r,c] #Standard form of the matrix.
matrix[1,2] #Extract element in the first row and second column
[1] 2
#Extract the entire first row and second columns
matrix[,1:2]
[,1] [,2]
[1,] 1 2
[2,] 5 6
[3,] 9 10
[4,] 13 14
Assign dimension
names to Matrix
rownames(matrix) <- c("Yes", "No", "Perhaps", "Maybe")
colnames(matrix) <- c("Apple", "Pear", "Banana", "Grapes")
matrix
Apple Pear Banana Grapes
Yes 1 2 3 4
No 5 6 7 8
Perhaps 9 10 11 12
Maybe 13 14 15 16
Dimension of a
matrix vs vector
x <- c(1,2,3)
matrix<-matrix(1:4, byrow = TRUE, nrow = 2)
length(x)
[1] 3
[1] 4
[1] 2 2
NULL
Lists
R doesn’t like vectors to have different types:
c(TRUE, 1, "Frank") becomes
c("TRUE", "1", "Frank"). But storing objects with different
types is absolutely fundamental to data analysis. R has a
different type of object besides a vector used to store data of
different types side-by-side: a list:
[1] "TRUE" "1" "Frank"
x <- list(TRUE, 1, "Frank")
x
[[1]]
[1] TRUE
[[2]]
[1] 1
[[3]]
[1] "Frank"
Many different things not necessarily of same length can be put
together.
x <- list(c(1:5), c("a", "b","c"), c(TRUE, FALSE), c(5L, 6L))
x
[[1]]
[1] 1 2 3 4 5
[[2]]
[1] "a" "b" "c"
[[3]]
[1] TRUE FALSE
[[4]]
[1] 5 6
Dataframes
- Data frames are like spreadsheet data, rectangular with rows and
columns.
- Ideally each row represents data on a single observation and each
column contains data on a single variable, or characteristic, of the
observation.
- It represents the data in a tabular format where the columns are
vectors that all have the same length. Because columns are vectors, each
column must contain a single type of data (e.g., characters, integers,
factors).
- We can open a data viewer window to see the contents of
R’s iris data frame by typing.
- We will be working with spreadsheets a lot.
Create a data
frame
Data frame with Harry Potter characters
name <- c("Harry", "Ron", "Hermione", "Hagrid", "Voldemort")
height <- c(176, 175, 167, 230, 180)
gpa <- c(3.4, 2.8, 4.0, 2.2, 3.4)
df_students <- data.frame(name, height, gpa)
df_students
Alternative way of creating DF
df_students <- data.frame(name = c("Harry", "Ron", "Hermione", "Hagrid", "Voldemort"),
height = c(176, 175, 167, 230, 180),
gpa = c(3.4, 2.8, 4.0, 2.2, 3.4))
df_students
Adding variable
df_students$good <- c(1, 1, 1, 1, 0)
df_students
Features of the
DF
dim(df_students)
df_students[2, 3] #Ron's GPA
df_students$gpa[2] #Ron's GPA
df_students[5, ] #get row 5
df_students[3:5, ] #get rows 3-5
df_students[, 2] #get column 2 (height)
df_students$height #get column 2 (height)
df_students[, 1:3] #get columns 1-3
df_students[4, 2] <- 255 #reassign Hagrid's height
df_students$height[4] <- 255 #same thing as above
df_students
Exercise
Now that you are equipped with the basic, go ahead and take the
following Datacamp Course, R
Intro on Datacamp. Your invitations should now be in your inbox.
Part IV: Working
directories
You can use the
command to obtain the current directory R is using.
It is good practice to set the working directory location to where
the files and data are stored.
- Consider setting your working directory to a folder called AAEC4984,
AAEC5484, or STAT5484 on your desktop (for example).
Creating Directory
and Set working directory
Windows
setwd("C:/users/[your user name]/Desktop/AAEC4984/")
# OR
setwd("C:\\users\\[your user name]\\Desktop\\AAEC4984\\")
# notice the double backslashes
Mac
setwd("~/Desktop/AAEC4984")
- To check whether the wd is correct, we again use
- To obtain a list of the names of files or folders in the working
directory, we can use
- To create a new folder in your directory we can use
dir.create("[Folder name]")
Importing data
R allows us to import several file types. I will discuss
3 that we are most likely to use in this course.
- Text files
-
Data sometimes come with headers (the first row is variable names, not
actual data!) You need to tell R that!
textdata<-read.table("examples/hogsdata.txt",header=T)
- CSV files :
- xlsx files (requires openxlsx package)
xlsxdata <- read.csv("examples/hogsdata.xlsx", ... )
Functions &
Packages
Functions are “canned scripts” that automate more complicated sets of
commands including operations assignments, etc. For the purpose of this
course, we will use a lot of functions that are built both in base R
(that is, they are predfined) or available through R packages (discuss
below).
A function usually takes one or more inputs called
arguments, and often (but not always) return a
value.
Consider for example, taking the average of a set of random numbers
(x).
set.seed(124)
x <- rnorm(6) * 100
(round(x, digits=2)) # round function => 2dp
[1] -138.51 3.83 -76.30 21.23 142.55 74.45
If we were to do this manually, we would:
- Sum up the values
- Get the number of observations
- Divide sum by total number of observations
Using R’s built in mean function we can do
all three steps internally and cross check against our manual
calculations.
[1] 4.542439
meanx == mean(x) # cross validation
[1] TRUE
Installing
Packages
Since R is an Open Source software program, thousands of
people contribute to the software. They do this by writing commands
(called functions) to make a particular analysis easier, or to make a
graphic prettier.
When you download R, you get access to a lot of
functions that we will use. However the other user-written packages we
use for our analyses will make our lives much easier.
For example, though we can use the plot command for
standard graphics, you will quickly see that we can get much better
looking time series graphs using the fpp3 package (which
also uses, among other packages,ggplot2).
Installing
Packages
To install the fpp2 package, we can use the command
We will need to install a package only once in R.
Now that you have the fpp3 package installed, we can
check to see if it is in use
Lastly, in order to use the package, we will need to load the
library
Using libraries
The fpp3 package contains a number of useful datasets.
One such data set is us_gasoline (Weekly US finished motor
gasoline product supplied).
Use the help() function to get a description of this
data. Try
Now let us create a nice plot of the us_gasoline
data.
autoplot(us_gasoline, col = "darkgreen") +
#Now to add axis labels
labs(title = "Weekly US finished motor gasoline product supplied",
y = "Mbd", caption = "Source: fpp3 package") +
theme_light() # One of many themes in R

Let us leave it there for now!
LS0tDQp0aXRsZTogIlNob3J0IEludHJvZHVjdGlvbiB0byBSIg0Kc3VidGl0bGU6ICdUdXRvcmlhbCBvbiBSIFN0dWRpbycNCiMgbG9nbzogLi4vaW1hZ2VzL3JzdHVkaW8tc3RhcnQucG5nDQphdXRob3I6IEFwcGxpZWQgRWNvbm9taWMgRm9yZWNhc3RpbmcNCiNpbnN0aXR1dGU6IHwNCiMgIHwgRGVwYXJ0bWVudCBvZiBBZ3JpY3VsdHVyYWwgJiBBcHBsaWVkIEVjb25vbWljcw0KIyAgfCBWaXJnaW5pYSBUZWNoDQojIGRhdGU6ICIxLzE4LzIwMjEiDQpvdXRwdXQ6IA0KICBodG1sX25vdGVib29rOg0KICAgIHRoZW1lOiBqb3VybmFsDQogICAgaGlnaGxpZ2h0OiB6ZW5idXJuDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDMNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgIGZvbnR0aGVtZTogInNlcmlmIg0KICAgIGNvZGVfZm9sZGluZzogc2hvdw0KLS0tDQoNCmBgYHtyIHNldHVwLCBlY2hvPUZBTFNFLCBpbmNsdWRlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfSANCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UpDQpyZXF1aXJlKGZwcDMpDQp0aGVtZV9zZXQodGhlbWVfYncoKSkNCmBgYA0KDQojIFBhcnQgSTogYFJgIEludHJvZHVjdGlvbg0KDQojIyBXaGF0IGlzIGBSYD8NCg0KYFJgIGlzIGEgKipwcm9ncmFtbWluZyBsYW5ndWFnZSoqIHVzZWQgZm9yIHN0YXRpc3RpY2FsIGFuYWx5c2lzIGFuZCBncmFwaGljcy4gSXQgaXMgYmFzZWQgb24gUy1wbHVzLCB3aGljaCBpdHNlbGYgd2FzIGJhc2VkIG9uIFMsIGEgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2Ugb3JpZ2luYWxseSBkZXZlbG9wZWQgYnkgQVQmVC4gDQoNCiMjIFdoeSBgUmA/DQoNCi0gT3BlbiBzb3VyY2UsIGNyb3NzLXBsYXRmb3JtLCBhbmQgKipmcmVlKioNCi0gR3JlYXQgZm9yIHJlcHJvZHVjaWJpbGl0eQ0KLSBJbnRlcmRpc2NpcGxpbmFyeSBhbmQgZXh0ZW5zaWJsZQ0KLSBUb25zIG9mIGxlYXJuaW5nIHJlc291cmNlcw0KLSBXb3JrcyBvbiBkYXRhIG9mIGFsbCBzaGFwZXMgYW5kIHNpemVzDQotIFByb2R1Y2VzIGhpZ2gtcXVhbGl0eSBncmFwaGljcw0KLSBMYXJnZSBhbmQgd2VsY29taW5nIGNvbW11bml0eQ0KDQoNCiMjIGBSYDogT2JqZWN0LU9yaWVudGVkIFByb2dyYW1taW5nDQoNClVubGlrZSBtYW55IG90aGVyIHN0YXRpc3RpY2FsIHNvZnR3YXJlIHN1Y2ggYXMgU0FTIGFuZCBTUFNTLCBgUmAgd2lsbCBub3Qgc3BpdCBvdXQgYSBtb3VudGFpbiBvZiBvdXRwdXQgb24gdGhlIHNjcmVlbi4NCg0KSW5zdGVhZCwgYFJgIHJldHVybnMgYW4gKipvYmplY3QqKiBjb250YWluaW5nIGFsbCB0aGUgcmVzdWx0cy4gWW91LCBhcyBhbiB1c2VyLCBoYXZlIHRoZSBmbGV4aWJpbGl0eSB0byBjaG9vc2Ugd2hpY2ggcmVzdWx0IHRvIGJlIGV4dHJhY3RlZCBvciByZXBvcnRlZC4NCg0KDQojIyBgUmA6IEZ1bmN0aW9uYWwgUHJvZ3JhbW1pbmcNCg0KVGhpcyBmZWF0dXJlIGFsbG93cyB1cyB0byB3cml0ZSBmYXN0ZXIgeWV0IG1vcmUgY29tcGFjdCBjb2RlLiBGb3IgZXhhbXBsZSwgYSBjb21tb24gdGhlbWUgaW4gYFJgIHByb2dyYW1taW5nIGlzICoqYXZvaWRhbmNlIG9mIGV4cGxpY2l0IGl0ZXJhdGlvbioqLiBVbmxpa2UgbWFueSBvdGhlciBzdGF0aXN0aWNhbCBzb2Z0d2FyZXMsIGV4cGxpY2l0IGxvb3BzIGFyZSBkaXNjb3VyYWdlZC4NCg0KDQpJbnN0ZWFkLCBgUmAgcHJvdmlkZXMgc29tZSBmdW5jdGlvbnMgdGhhdCBjb3VsZCBhbGxvdyB1cyB0byBleHByZXNzIGl0ZXJhdGl2ZSBiZWhhdmlvciBpbXBsaWNpdGx5Lg0KDQoNCiMjIGBSYDogUG9seW1vcnBoaWMNCg0KYFJgIGlzIGFsc28gKnBvbHltb3JwaGljKiwgd2hpY2ggbWVhbnMgdGhhdCBhIHNpbmdsZSBmdW5jdGlvbiBjYW4gYmUgYXBwbGllZCB0byBkaWZmZXJlbnQgdHlwZXMgb2YgaW5wdXRzIChtdWNoIG1vcmUgdXNlciBmcmllbmRseSkuDQoNClN1Y2ggYSBmdW5jdGlvbiBpcyBjYWxsZWQgYSAqZ2VuZXJpYyBmdW5jdGlvbiogKElmIHlvdSBhcmUgYSBDKysgcHJvZ3JhbW1lciwgeW91IGhhdmUgc2VlbiBhIHNpbWlsYXIgY29uY2VwdCBpbiAqdmlydHVhbCBmdW5jdGlvbnMqKS4NCg0KIyMgUG9seW1vcnBoaWMgLSBFeGFtcGxlDQoNCkxldHMgbG9vayBhdCBvbmUgZXhhbXBsZSBgcGxvdCgpYA0KDQoxLiBQbG90IGEgdmVjdG9yIG9mIG51bWJlcnMNCjIuIFBsb3Qgc29tZSBtb2RlbCByZXN1bHRzDQoNCk5vIG1hdHRlciB3aGljaCBwdXJwb3NlLCB3ZSB1c2UgdGhlIHNhbWUgZnVuY3Rpb24uDQoNCmBgYHtyLCBlY2hvPVRSVUUsIGZpZy5oZWlnaHQ9NH0NCmRhdHMgPC0gYygxLDIsMyw0KQ0KcGxvdChkYXRzKQ0KYGBgDQoNCg0KYGBge3IsIGVjaG89VFJVRSwgZmlnLnNob3c9ImhvbGQiLCBmaWcuaGVpZ2h0PTV9DQojIFJlZ3Jlc3Npb24gQW5hbHlzaXMNCnBhcihtZnJvdz1jKDIsMiksbWFyPWMoMiw0LDIsMikpDQpyZXN1bHRzIDwtIGxtKHNwZWVkIH4gZGlzdCxkYXRhPWNhcnMpDQpwbG90KHJlc3VsdHMpDQpgYGANCg0KDQojIyBXaHkgUiBTdHVkaW8/DQoNCi0gYFJgIEludGVyZmFjZSBpcyAqKnVnbHkqKiENCg0KDQotIE1hbnkgc3R1ZGVudHMgaW4gdGhpcyBjbGFzcyBhcmUgbXVjaCBtb3JlIGZhbWlsaWFyIHdpdGggV2luZG93cyBvcGVyYXRpb24gc3lzdGVtIGFuZCBoYXZlIG5ldmVyIGJlZW4gZXhwb3NlZCBwcm9ncmFtbWluZyBiZWZvcmUsIHNvIHdlIHdpbGwgdXNlIFIgc3R1ZGlvLCBvbmUgb2YgdGhlIGZyZWUgR3JhcGhpY2FsIFVzZXIgSW50ZXJmYWNlcyAoR1VJcykgdGhhdCBoYXZlIGJlZW4gZGV2ZWxvcGVkIGZvciBgUmAuDQoNCi0gUiBzdHVkaW8gc2hvdWxkIHJlYWxseSBiZSBjb25zaWRlcmVkIGFzICppbnRlZ3JhdGVkIGRldmVsb3BtZW50IGVudmlyb25tZW50cyogKElERXMpLCBzaW5jZSBpdCBpcyBhaW1lZCBtb3JlIHRvd2FyZCBwcm9ncmFtbWluZy4NCg0KLSBFYXN5IHB1Ymxpc2hpbmcgb2YgcmVwcm9kdWNpYmxlIGRvY3VtZW50cyBzdWNoIGFzIHJlcG9ydHMsIGludGVyYWN0aXZlIHZpc3VhbGl6YXRpb25zLCBwcmVzZW50YXRpb25zLCBhbmQgd2Vic2l0ZXMuDQoNCiMjIFIgU3R1ZGlvOiBBIHNob3J0IHRvdXINCg0KKipJbml0aWFsIFN0YXJ0KioNCg0KV2hlbiB5b3UgZmlyc3QgKGxpa2UgdmVyeSBmaXJzdCB0aW1lKSBvcGVuIFIgc3R1ZGlvIHlvdSB3aWxsIHNlZSB0aHJlZSBwYW5lbHMuDQoNCg0KIVtdKC4uL2ltYWdlcy9yc3R1ZGlvLXN0YXJ0LnBuZykNCg0KLS0tDQoNCioqQ29uc29sZSoqDQoNCiFbXSguLi9pbWFnZXMvcnN0dWRpby1jb25zb2xlLnBuZyl7c2NhbGU9MzAlfQ0KDQoxLiBFdmVyeSB0aW1lIHlvdSBsYXVuY2ggUlN0dWRpbywgaXQgd2lsbCBoYXZlIHRoZSBzYW1lIHRleHQgYXQgdGhlIHRvcCBvZiB0aGUgY29uc29sZSB0ZWxsaW5nIHlvdSB0aGUgdmVyc2lvbiBvZiBSIHRoYXQgeW91J3JlIHJ1bm5pbmcuDQoyLiBCZWxvdyB0aGF0IGluZm9ybWF0aW9uIGlzIHRoZSBwcm9tcHQsIGA+YCAuIEFzIGl0cyBuYW1lIHN1Z2dlc3RzLCB0aGlzIHByb21wdCBpcyByZWFsbHkgYSByZXF1ZXN0LCBhIHJlcXVlc3QgZm9yIGEgY29tbWFuZC4NCjMuIEluaXRpYWxseSwgaW50ZXJhY3Rpbmcgd2l0aCBSIGlzIGFsbCBhYm91dCB0eXBpbmcgY29tbWFuZHMgYW5kIGludGVycHJldGluZyB0aGUgb3V0cHV0Lg0KNC4gVGhlc2UgY29tbWFuZHMgYW5kIHRoZWlyIHN5bnRheCBoYXZlIGV2b2x2ZWQgb3ZlciBkZWNhZGVzIChsaXRlcmFsbHkpIGFuZCBub3cgcHJvdmlkZSB3aGF0IG1hbnkgdXNlcnMgZmVlbCBpcyBhIGZhaXJseSBuYXR1cmFsIHdheSB0byBhY2Nlc3MgZGF0YSBhbmQgb3JnYW5pemUsIGRlc2NyaWJlLCBhbmQgaW52b2tlIHN0YXRpc3RpY2FsIGNvbXB1dGF0aW9ucy4NCg0KDQpUaGUgY29uc29sZSBpcyB3aGVyZSB5b3UgdHlwZSBjb21tYW5kcyBhbmQgaGF2ZSB0aGVtIGltbWVkaWF0ZWx5IHBlcmZvcm1lZC4NCg0KLS0tDQoNCioqRW52aXJvbm1lbnQqKg0KDQpUaGUgcGFuZWwgaW4gdGhlIHVwcGVyIHJpZ2h0IGNvbnRhaW5zIHlvdXIgd29ya3NwYWNlIChha2EgRW52aXJvbm1lbnQpDQoNCiFbXSguLi9pbWFnZXMvcnN0dWRpby1lbnYucG5nKQ0KDQoxLiBUaGlzIHNob3dzIHlvdSBhIGxpc3Qgb2Ygb2JqZWN0cy92YXJpYWJsZXMgdGhhdCBSIGhhcyBzYXZlZC4NCjIuIEZvciBleGFtcGxlIGhlcmUgYSB2YWx1ZSBvZiBgM2AgaGFzIGJlZW4gYXNzaWduZWQgdG8gdGhlIG9iamVjdCBgYWAuDQoNCi0tLQ0KDQoqKkhpc3RvcnkqKg0KDQpVcCBoZXJlIHRoZXJlIGlzIGFuIGFkZGl0aW9uYWwgdGFiIHRvIHNlZSB0aGUgaGlzdG9yeSBvZiB0aGUgY29tbWFuZHMgdGhhdCB5b3UndmUgcHJldmlvdXNseSBlbnRlcmVkLg0KDQoNCg0KIVtdKC4uL2ltYWdlcy9yc3R1ZGlvLWhpc3RvcnkucG5nKQ0KDQoNCi0tLQ0KDQoqKkZpbGVzKioNCg0KVGhlIGZpbGVzIHRhYiBhbGxvd3MgeW91IHRvIG9wZW4gY29kZS9zY3JpcHQgZmlsZXMgd2l0aGluIFIgc3R1ZGlvLg0KDQoNCiFbXSguLi9pbWFnZXMvcnN0dWRpby1maWxlcy5wbmcpDQoNCi0tLQ0KDQoqKlBsb3RzKioNCg0KQW55IHBsb3RzIHRoYXQgeW91IGdlbmVyYXRlIHdpbGwgc2hvdyB1cCBpbiB0aGUgcGFuZWwgaW4gdGhlIGxvd2VyIHJpZ2h0IGNvcm5lci4NCg0KDQohW10oLi4vaW1hZ2VzL3JzdHVkaW8tcGxvdC5wbmcpDQoNCi0tLQ0KDQoqKkhlbHAqKg0KDQpUbyBjaGVjayB0aGUgc3ludGF4IG9mIGFueSBmdW5jdGlvbiBpbiBSLCB0eXBlID8gaW4gZnJvbnQgb2YgdGhlIGZ1bmN0aW9uIG5hbWUgdG8gcHVsbCB1cCB0aGUgaGVscCBmaWxlLg0KDQoNCiFbXSguLi9pbWFnZXMvcnN0dWRpby1oZWxwLnBuZykNCg0KRm9yIGV4YW1wbGUgaGVyZSBJIHR5cGVkIGA/bWVhbmAgdG8gZ2V0IHRoZSBoZWxwIGZpbGUgZm9yIHRoZSBtZWFuIGZ1bmN0aW9uLiBUaGUgaGVscCBmaWxlcyBhcmUgbm90IGFsd2F5cyB0aGUgbW9zdCB1c2VmdWwgYnV0IGFyZSB1c3VhbGx5IGEgZ29vZCBwbGFjZSB0byBzdGFydC4NCg0KLS0tDQoNCioqU2NyaXB0IEZpbGUqKiBUaGUgdG9wIGxlZnQgaXMgeW91ciBlZGl0b3Igd2luZG93LCB3aGVyZSB5b3Ugd3JpdGUgY29kZSBvciBzY3JpcHQsIHRoZSBjb25zb2xlIGlzIG5vdyBhdCB0aGUgYm90dG9tLiAqKkkgdXN1YWxseSBjaGFuZ2UgaXQqKg0KDQohW10oLi4vaW1hZ2VzL3JzdHVkaW8tY2hhbmdlZC5wbmcpDQoNClRoZSBwaWN0dXJlIGFib3ZlIGlsbHVzdHJhdGVzIG15IHByZWZlcnJlZCBzdHlsZSBpbiBSIFN0dWRpby4NCg0KDQojIyBSIFNjcmlwdA0KDQpNb3N0IG9mIGBSYCB1c2VycyB0eXBpY2FsbHkgc3VibWl0IGNvbW1hbmRzIHRvIGBSYCBieSB0eXBpbmcgZWl0aGVyIGluIGNvbnNvbGUgb3IgZWRpdG9yIHBhbmVsLCByYXRoZXIgdGhhbiBjbGlja2luZyBhIG1vdXNlIGluIGEgR3JhcGhpY2FsIFVzZXIgSW50ZXJmYWNlIChHVUkpLg0KDQpJbiBjbGFzcywgd2Ugd2lsbCBtYWtlIGV4dGVuc2l2ZSB1c2Ugb2Ygc2NyaXB0cy4gQSAqKlNjcmlwdCoqIGlzIG5vdGhpbmcgYnV0ICoqYSBjb2xsZWN0aW9uIG9mIGNvbW1hbmRzIGFuZCBwcm9jZWR1cmVzIHRoYXQgdGhlIGNvZGVyIHBlcmZvcm1lZCB0byBnZXQgdG8gdGhlaXIgcmVzdWx0cyBhbmQgY29uY2x1c2lvbnMuKiouDQoNClRoZXJlIGFyZSBhdCBsZWFzdCB0d28gYWR2YW50YWdlcyBvZiBkb2luZyBzbzoNCg0KMS4gQXMgZXhwbGFpbmVkIGVhcmxpZXIsIHRoaXMgYWxsb3dzIHVzIHRvIHJ1biBhIGJ1bmNoIG9mIHJlc3VsdHMgYWx0b2dldGhlciBieSBwdXR0aW5nIGEgY29sbGVjdGlvbiBvZiBjb21tYW5kcyBpbiBhIGZpbGUuDQoyLiBJdCBpcyBhbHNvIGEgbG90IG1vcmUgdHJhbnNwYXJlbnQgYW5kIHN0cmFpZ2h0Zm9yd2FyZCB0byAqKnNoYXJlKiogYW5kICoqcmVwbGljYXRlKiogd2hhdCB5b3UgaGF2ZSBkb25lLg0KDQo8cCBhbGlnbj0iY2VudGVyIj4gPGI+IFRoaXMgd2lsbCBhbHdheXMgYmUgb3VyIGFwcHJvYWNoIGluIHRoaXMgY2xhc3MhISEgPC9iPiA8L3A+DQoNCg0KIyMgUk1hcmtkb3duDQoNCllvdXIgYXNzaWdubWVudHMgd2lsbCB1c2UgYSBzbGlnaHRseSBkaWZmZXJlbnQgYXBwcm9hY2ggYXMgeW91IHdpbGwgYmUgcmVxdWlyZWQgdG8gcHJvZHVjZSBhIGAucGRmYCBmaWxlIHZpYSBhbiBgLlJtZGAgZmlsZS4gVGhpbmsgb2YgdGhpcyBhcyBhbiBpbnRlcmFjdGl2ZSB2ZXJzaW9uIG9mIHRoZSBSIFNjcmlwdC4gSGVyZSwgd2UgYXJlIGFibGUgdG8gZW1iZWQgb3VyIGNvZGVzIGFuZCByZXN1bHRzIHdpdGggbGl0dGxlIGVmZm9ydC4gDQpSTWFya2Rvd24gaXMgZm9jdXNlZCBvbiByZXByb2R1Y2liaWxpdHkgYW5kIGxlc3Mgb24gdGhlIHN0YXRpYyBjb2RlcyBwcmVzZW50ZWQgaW4geW91ciBSIHNjcmlwdHMuDQoNClRoZSBuZXh0IGxlc3NvbiBjb3ZlcnMgUk1hcmtkb3duIGZpbGVzIGFuZCBpdHMgZmxleGliaWxpdHkuDQoNCi0tLQ0KDQojIyBFeGVyY2lzZQ0KDQojIyMgKipUYXNrIDE6KiogQ3JlYXRlIGEgc2NyaXB0IGZpbGUNCg0KMS4gT3BlbiBSIFN0dWRpbyBhbmQgZ28gdG8gYEZpbGUgPiBOZXcgPiBSIFNjcmlwdGAuDQoNClRoaXMgd2lsbCBvcGVuIGEgYmxhbmsgdGV4dCBkb2N1bWVudC4NCg0KLSBUd28gYWx0ZXJuYXRpdmUgd2F5cyBhcmU6IA0KICAtICoqQ1RSTCArIFNISUZUICsgTioqIG9yDQogIC0gKipwcmVzcyB0aGUgYnV0dG9uIG1hcmtlZCAiKyIsIGp1c3QgYmVsb3cgRmlsZSwgYW5kIHNlbGVjdCBSIFNjcmlwdCoqDQoNCjIuIEluIHRoZSBkb2N1bWVudCwgdHlwZQ0KDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KeCA9IDUgICMgQXNzaWduIHRoZSB2YXJpYWJsZSB4IGEgdmFsdWUgb2YgNQ0KeCA9PSA1ICAjIERvZXMgeCA9IDU/IE5vdGljZSB0aGUgZG91YmxlID09DQpgYGANCg0KLSBIaWdobGlnaHQgYm90aCBsaW5lcyBvZiBjb2RlIGFuZCBjbGljayB0aGUgYnV0dG9uIG1hcmtlZCAiUnVuIi4gSWYgZXZlcnl0aGluZyBpcyB3b3JraW5nIGNvcnJlY3RseSwgdGhlIGNvbnNvbGUgc2hvdWxkIGRpc3BsYXkgYFRSVUVgLg0KDQotIE9SLCBwcmVzc2luZyAqKkNUUkwgKyBFTlRFUioqICBvciAqKkNPTU1BTkQgKyBSRVRVUk4qKiBkZXBlbmRpbmcgb24gd2hldGhlciB5b3UncmUgcnVubmluZyBNYWMgT1NYLCBMaW51eCBvciBXaW5kb3dzLg0KDQozLiBHbyB0byAiRmlsZSA+IFNhdmUgQXMiLCBhbmQgY2hvb3NlIGEgZmlsZSBuYW1lLg0KDQotLS0NCg0KIyBQYXJ0IElJOiBXb3JraW5nIHdpdGggU2NyaXB0cw0KDQojIyBDb21tZW50cw0KDQpXaGVuZXZlciBwb3NzaWJsZSwgdXNlIGNvbW1lbnRzISBBbnl0aGluZyBmb2xsb3dpbmcgdGhlIHN5bWJvbCBgI2AgaW4gYW4gKipSIFNjcmlwdCoqIHdpbGwgbm90IGJlIHJ1biBpbiBSLg0KDQpDb21tZW50cyBhcmUgbm90ZXMgd2UgbGVhdmUgb3Vyc2VsdmVzIHNvIHdlIGtub3c6DQoNCiAgLSBleGFjdGx5IHdobyB3cm90ZSB0aGUgY29kZSAoaW1wb3J0YW50IGluIGNvbXBhbmllcyB3aGVyZSBtYW55IHBlb3BsZSBtYXkgd29yayBvbiBhIHByb2plY3QpDQogIC0gdGhlIHB1cnBvc2Ugb2YgdGhlIGNvZGUhDQogIC0gd2hhdCBvdXIgdGhvdWdodCBwcm9jZXNzIHdhcyBhdCBhIHBhcnRpY3VsYXIgbGluZSBvZiBjb2RlLg0KDQpJIHByb21pc2UgdGhhdCB0aGlzIHdpbGwgYmVjb21lIHVzZWZ1bCB3aGVuIHlvdSBjb21lIGJhY2sgdG8geW91ciBjb2RlIGFmdGVyIGFuIGV4dGVuZGVkIHRpbWUuIEkgY2Fubm90IHRlbGwgeW91IHRoZSBudW1iZXIgb2YgdGltZXMgSSBoYXZlIGhhZCBhIG1vbWVudCBvZiBwdXJlIGdlbml1cyB3aGlsZSBjb2RpbmcgYW5kIEkgc3BlbmQgaG91cnMgb24gYSBkaWZmZXJlbnQgZGF5IHRyeWluZyB0byB1bmRlcnN0YW5kIHdoeSBJIGNvZGVkIGl0IGxpa2UgdGhhdCBvciB3aGF0IEkgYWN0dWFsbHkgZGlkLg0KDQotLS0NCg0KRm9yIGV4YW1wbGUsIGJlbG93IGlzIHRoZSB0eXBlIG9mIGNvbW1lbnRzIHRoYXQgSSBhbHdheXMgaW5jbHVkZSBpbiBteSBwcm9ncmFtcw0KYGBgDQojIFByb2plY3Q6ICdUdXRvcmlhbCBvbiBSIFN0dWRpbyBJSScNCiMgQXV0aG9yOiAgU2hhbWFyIFN0ZXdhcnQNCiMgVGhpcyBwcm9ncmFtIGlsbHVzdHJhdGVzIHNvbWUgYmFzaWMgcHJvZ3JhbW1pbmcgcGhpbG9zb3BoeQ0KIyBhbmQgUiBvcGVyYXRpb25zDQpgYGANCg0KWW91IGNhbiBhbHNvIHVuZGVyc3RhbmQgdGhlIGZvbGxvd2luZyBjb2RlIHdpdGhvdXQgZXZlbiBrbm93aW5nIHdoYXQgZXhhY3RseSBlYWNoIGxpbmUgb2YgY29tbWFuZCBkb2VzIGJlY2F1c2UgSSB0ZWxsIHlvdSB3aGF0IHRoZXkgYXJlIQ0KDQpgYGB7cn0NCiMgU2V0IHNlZWQgbnVtYmVyIHNvIHRoYXQgYWxsIHRoZSByZXN1bHRzIGJhc2VkIG9uIHJhbmRvbSBzYW1wbGVzDQojIGFyZSByZXByb2R1Y2libGUuDQogIHNldC5zZWVkKDEyMzQ1KQ0KIyBUaGVuIGNyZWF0ZSBhIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIHJhbmRvbSB2YXJpYWJsZSwgeCwgd2l0aCA1MDANCiMgb2JzZXJ2YXRpb25zLg0KICB4IDwtIHJub3JtKDUwMCkNCiMgTm90aWNlICI8LSIgaXMgdGhlIHVuaXZlcnNhbCBhc3NpZ25tZW50IG9wZXJhdG9yIGluIFIgKEkgcHJlZmVyIHRoaXMgdG8gIj0iKQ0KYGBgDQoNCi0tLQ0KDQojIyBFeGVyY2lzZQ0KIyMjICoqVGFzayAyOioqDQoNCkF0IHRoZSB0b3Agb2YgdGhlIHByZXZpb3VzIHNjcmlwdCAoVGFzayAxKSwgYWRkIGFuZCBleHBhbmQgb24gdGhlIGZvbGxvd2luZyBjb21tZW50czoNCg0KICAxLiBUaGUgcHJvamVjdA0KICAyLiBUaGUgYXV0aG9yDQogIDMuIFRoZSBwdXJwb3NlIG9mIHRoaXMgcHJvZ3JhbQ0KDQoqKkZvbGxvdyB0aGUgZXhhbXBsZSBnaXZlbiBhYm92ZS4qKg0KDQotLS0NCg0KIyMgUiBCYXNpY3MNCg0KKipBcml0aG1ldGljKioNCg0KYGBge3J9DQoNCiAgMSArIDEgI2FkZCBudW1iZXJzDQoNCiAgOCAtIDQgI3N1YnRyYWN0IHRoZW0NCg0KICAxMy8yICNkaXZpZGUNCg0KICA0KnBpICNtdWx0aXBseSAoUGkgaXMgYSBidWlsdCBpbiBmdW5jdGlvbiBpbiBSKQ0KDQogIDJeMTAgI2V4cG9uZW50aWF0ZQ0KYGBgDQoNCi0tLQ0KDQojIyBMb2dpY2FsIENvbXBhcmlzb24NCg0KTG9naWNhbCBhcmd1bWVudHMgd2lsbCByZXN1bHQgaW4gYSB2YWx1ZSBvZiBgVFJVRWAgb3IgYEZBTFNFYC4NCg0KDQpgYGB7cn0NCiAgMyA8IDQNCiAgMyA+IDQNCiAgMyA9PSA0DQogIDMgIT0gNA0KICAxMCAtIDYgPT0gNA0KDQogICMgTm90aWNlIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gc2luZ2xlIGFuZCBkb3VibGUgZXF1YWwgc2lnbnMNCmBgYA0KDQpOb3cgdHJ5IGAzID0gNGAuIFdoYXQgaXMgdGhlIHJlc3VsdCBoZXJlPw0KDQojIyBTdHJpbmdzICh0ZXh0KQ0KDQpgYGB7cn0NCiNSIGRlbGltaXRzIHN0cmluZ3Mgd2l0aCBFSVRIRVIgZG91YmxlIG9yIHNpbmdsZSBxdW90ZXMuDQojVGhlcmUgaXMgb25seSBhIHZlcnkgbWluaW1hbCBkaWZmZXJlbmNlDQoNCm1lc3NhZ2UxIDwtICdMZXQgdXMgZ2V0IHRvIGNvZGluZyEnDQptZXNzYWdlMiA8LSAgIlBsZWFzZSBnZXQgdG8gY29kaW5nISINCnByaW50KG1lc3NhZ2UxKQ0KcHJpbnQobWVzc2FnZTIpDQpgYGANCg0KSW4gUiwgd2UgY2FuIGFsc28gcHJpbnQgdGhlIHJlc3VsdChzKSBzdG9yZWQgaW4gb3VyIHZhcmlhYmxlcyBieSBzaW1wbHkgcnVubmluZyB0aGUgcnVubmluZyB0aGUgdmFyaWFibGUgbmFtZSBpbnN0ZWFkIG9mIGBwcmludCgpYC4NCg0KYGBge3J9DQptZXNzYWdlMQ0KYGBgDQoNCg0KIyMgVmFyaWFibGVzDQoNCi0gdmFyaWFibGUgYXJlIHVzZWQgdG8gc3RvcmUgdmFsdWVzIGFuZCByZXN1bHRzLiBBc3NpZ25tZW50IHRvIGEgdmFyaWFibGUgaGFwcGVucyBmcm9tIHJpZ2h0IHRvIGxlZnQgLSB0aGUgdmFsdWUgb24gdGhlIHJpZ2h0IHNpZGUgZ2V0cyBhc3NpZ25lZCB0byB0aGUgbmFtZSBvbiB0aGUgbGVmdCBzaWRlLiBZb3UgY2FuIHVzZSBuZWFybHkgYW55dGhpbmcgYXMgYSB2YXJpYWJsZSBuYW1lIGluIFIuIFRoZSBvbmx5IHJ1bGVzIGFyZToNCg0KMS4gIi4iIGFuZCAiXyIgYXJlIE9LIHRvIGJlIGFkZGVkIHRvIHZhcmlhYmxlIG5hbWVzLCBidXQgbm8gb3RoZXIgc3ltYm9scy4NCg0KMi4gWW91ciB2YXJpYWJsZSBuYW1lIG11c3Qgbm90IHN0YXJ0IHdpdGggYSBudW1iZXIgb3IgIl8iIChgMnNxdWFyZWRgIGFuZCAgYF9vbmVgIGFyZSBpbGxlZ2FsKS4NCg0KLSBBIG5vdGUgZm9yIHRob3NlIG9mIHlvdSB3aG8gaGF2ZSBwcm9ncmFtbWluZyBleHBlcmllbmNlOiB3aGlsZSBSIHN1cHBvcnRzIG9iamVjdC1vcmllbnRlZCBwcm9ncmFtbWluZywgcGVyaW9kcyAiLiIgZG8gbm90IGhhdmUgYSBzcGVjaWFsIG1lYW5pbmcgaW4gdGhlIGxhbmd1YWdlLiBGb3IgaGlzdG9yaWNhbCByZWFzb25zLCBSIHByb2dyYW1tZXJzIG9mdGVuIHVzZSBwZXJpb2RzIGluIHBsYWNlIG9mIHVuZGVyc2NvcmVzIGluIHZhcmlhYmxlIG5hbWVzLCBidXQgZWl0aGVyIHdvcmtzLiBKdXN0IGJlIGNvbnNpc3RlbnQgdG8ga2VlcCB5b3VyIGNvZGUgcmVhZGFibGUuDQoNCi0gYFJgIGlzIGNhc2Ugc2Vuc2l0aXZlLiBDYXBpdGFsaXphdGlvbiBvZiB2YXJpYWJsZSBuYW1lcyBtYXR0ZXIuDQoNCmBgYHtyfQ0KICAgIHggPC0gNDINCiAgICB4IC8gMg0KDQogICAgIyByZWRlZmluZSB4DQogICAgeCA8LSB4ICsgMw0KICAgIHgNCg0KICAgICNpZiB3ZSBhc3NpZ24gc29tZXRoaW5nIGVsc2UgdG8geCwgdGhlIG9sZCB2YWx1ZSBpcyBkZWxldGVkDQogICAgeCA8LSAiSG9raWVzISINCiAgICB4DQoNCiAgICBmb28gPC0gMw0KICAgIGJhciA8LSA1DQogICAgZm9vLmJhciA8LSBmb28gKyBiYXINCiAgICBmb28uYmFyDQpgYGANCg0KDQotLS0NCg0KIyMgRXhlcmNpc2UNCg0KIyMjICoqVGFzayAzOioqDQoNCjEuIENyZWF0ZSBhIHZhcmlhYmxlIGNhbGxlZCBgZW50cnlgIHRoYXQgc3RvcmVzIHRoZSB5ZWFyIHlvdSBzdGFydGVkIGF0IFZpcmdpbmlhIFRlY2guDQoyLiBTdG9yZSB0aGUgY3VycmVudCB5ZWFyIHRvIGEgdmFyaWFibGUgY2FsbGVkIGBjdXJyZW50X3RgLg0KMi4gQ29tcHV0ZSB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIGBjdXJyZW50X3RgIGFuZCBgZW50cnlgLiBTdG9yZSB0aGlzIGFzIGBkaWZmc2AuDQozLiBTdG9yZSB5b3VyIGJpcnRoIHllYXIgYXMgYG15X3llYXJgLiBOb3cgY29tcHV0ZSB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIGBjdXJyZW50X3RgIGFuZCBgbXlfeWVhcmAuIEFzc2lnbiB0aGUgcmVzdWx0cyB0byBgbXlfZGlmZnNgLg0KNS4gVXNlIHRoaXMgaW5mb3JtYXRpb24gdG8gY29tcHV0ZSB0aGUgcGVyY2VudGFnZSBvZiB5b3VyIGxpZmUgaGF2ZSBzcGVudCBhdCB0aGlzIHVuaXZlcnNpdHkuIEJlIHN1cmUgdG8gdXNlIGJyYWNrZXRzIGlmIHlvdSBuZWVkIHRoZW0uDQo2LiBBc3NpZ24gdGhpcyByZXN1bHQgdG8gYSB2YXJpYWJsZSBvZiB5b3VyIGNob29zaW5nLg0KDQotLS0NCg0KIyMgQ2xlYXJpbmcgdGhlIG1lbW9yeQ0KDQpUbyByZW1vdmUgYWxsIHZhcmlhYmxlcyBpbiBtZW1vcnk6DQoNCmBgYHtyfQ0KIyAgICBscygpICMgTGlzdCBvZiBhbGwgdmFyaWFibGVzIGluIG1lbW9yeQ0KICAgIHJtKGxpc3Q9bHMoKSkNCmBgYA0KDQotICoqSSB1c3VhbGx5IHBsYWNlIHRoaXMgYXQgdGhlIGJlZ2lubmluZyBvZiBteSBgUmAgc2NyaXB0IChqdXN0IGFmdGVyIHRoZSBkb2N1bWVudCBkZXRhaWxzKS4qKiBJdCBpcyB1c3VhbGx5IGEgZ29vZCBpZGVhIHRvIGNsZWFyIHlvdXIgbWVtb3J5IGFmdGVyIHlvdSd2ZSBiZWVuIGRvaW5nIGEgbG90IG9mIGRlYnVnZ2luZy4gVGhpcyBlbnN1cmVzIHRoYXQgeW91ciBjb2RlcyB3aWxsIHdvcmsgZm9yIG90aGVycyBhbmQgaXMgbm90IGRlcGVuZGVudCBvZiB2YXJpYWJsZXMgeW91IGNyZWF0ZWQgYWxvbmcgdGhlIHdheSBidXQgZGlkbid0IGFjdHVhbGx5IGluY2x1ZGUgYXMgYSBwYXJ0IG9mIHlvdXIgc2NyaXB0Lg0KDQoNCiMgUGFydCBJSUk6IGBSYCBEYXRhIHR5cGVzDQoNCiMjIERhdGEgdHlwZXMgaW4gYFJgDQoNCllvdSBoYXZlIG9ic2VydmVkIGEgZmV3IG9mIHRoZSBkaWZmZXJlbnQgZGF0YSB0eXBlcyBpbiB0aGUgZWFybGllciBzZWN0aW9ucy4gSGVyZSwgd2Ugd2lsbCBmb3JtYWxseSBkaXNjdXNzIHRoZW0uIFNvbWUgb2YgdGhlIG1vc3QgYmFzaWMgZGF0YSB0eXBlcyB3ZSB3aWxsIGNvdmVyIGFyZToNCg0KICAxLiAqKkRlY2ltYWwgdmFsdWVzKiogbGlrZSA0LjUgYXJlIGNhbGxlZCBudW1lcmljcy4NCiAgMi4gKipOYXR1cmFsIG51bWJlcnMqKiAgbGlrZSA0IGFyZSBjYWxsZWQgaW50ZWdlcnMuIEludGVnZXJzIGFyZSBhbHNvIG51bWVyaWNzLg0KICAzLiAqKkJvb2xlYW4gdmFsdWVzKiogIChUUlVFIG9yIEZBTFNFKSBhcmUgYWxzbyBjYWxsZWQgbG9naWNhbC4NCiAgNC4gKipUZXh0KiogIChvciBzdHJpbmcpIHZhbHVlcyBhcmUgY2FsbGVkIGNoYXJhY3RlcnMuDQoNCg0KWW91IGNhbiBjaGVjayB0aGUgdHlwZSBvZiBkYXRhIGJ5IHVzaW5nIGBjbGFzcygpYC4NCg0KYGBge3J9DQogIHggPC0gIkx5cmljcyB0byBWaXJnaW5pYSBUZWNoIEZpZ2h0IFNvbmchIg0KICBjbGFzcyh4KQ0KDQogIHgyIDwtIGMoIlRSVUUiLCAiRkFMU0UiKQ0KICB4MiA8LSBhcy5sb2dpY2FsKHgyKSAjRGVjbGFyZSB0aGUgZGF0YSB0eXBlDQogIHgyDQogIGNsYXNzKHgyKQ0KDQogIHggPC0gMToyMA0KICB4ICUlIDQgI3ggbW9kIDQNCiAgeCAlJSA0ID09IDANCiAgY2xhc3MoeCAlJSA0ID09IDApDQpgYGANCg0KDQojIyBWZWN0b3JzDQoNCg0KQSB2ZWN0b3IgaXMgdGhlIG1vc3QgY29tbW9uIGFuZCBiYXNpYyBkYXRhIHR5cGUgaW4gUiwgYW5kIGlzIHByZXR0eSBtdWNoIHRoZSB3b3JraG9yc2Ugb2YgUi4gQSB2ZWN0b3IgaXMgY2hhcmFjdGVyaXplZCBieSBhIHNlcmllcyBvZiB2YWx1ZXMsIHdoaWNoIGNhbiBiZSBlaXRoZXIgbnVtYmVycyBvciBjaGFyYWN0ZXJzLiBXZSBjYW4gYXNzaWduIGEgc2VyaWVzIG9mIHZhbHVlcyB0byBhIHZlY3RvciB1c2luZyB0aGUgYGMoKWAgZnVuY3Rpb24uDQoNCkluIHNob3J0LCB2ZWN0b3JzIGFyZSBtb3N0IHVzZWZ1bCB3aGVuIHdlIGhhdmUgYSBjb2xsZWN0aW9uIG9mIGRhdGEgcG9pbnRzLg0KDQpIZXJlIGBjKClgIHN0YW5kcyBmb3IgKipjb25jYXRlbmF0ZSoqIG9yICoqY29tYmluZSoqLg0KDQoNCmBgYHtyfQ0KKHYgPC0gYygxLCAyLCAzLCA0KSkNCih2IDwtIDE6NCkNCih2IDwtIHNlcShmcm9tID0gMCwgdG8gPSAwLjUsIGJ5ID0gMC4xKSkNCg0KI0EgdmVjdG9yIGNhbiBhbHNvIGNvbnRhaW4gY2hhcmFjdGVyczoNCih2X2NvbG9ycyA8LSBjKCJibHVlIiwgInllbGxvdyIsICJsaWdodCBncmVlbiIpCSkNCg0KYGBgDQoNCjxiPiBOb3RpY2UgdGhhdCBieSBlbmNhc2luZyB0aGUgYmVnaW5uaW5nIGFuZCBlbmQgb2YgdGhlIGFzc2lnbm1lbnQgbGluZXMgaW4gcGFyZW50aGVzZXMsIHdlIGltbWVkaWF0ZWx5IHByaW50IHRoZSBzdG9yZWQgdmFsdWVzLiA8L2I+DQoNCiMjIFN1YnNldHRpbmcgdmVjdG9ycyAoSW5kZXhpbmcvcmVhc3NpZ25pbmcgZWxlbWVudHMpDQoNCldlIGFyZSBhYmxlIHRvIGluZGV4IChjb2xsZWN0IHN1YnNldHMgb2Ygb3VyIHZhcmlhYmxlcykgYnkgdXNpbmcgc3F1YXJlZCBicmFja2V0cy4gVW5saWtlIHB5dGhvbiwgZm9yIGV4YW1wbGUsIFIncyBpbmRleGluZyBiZWdpbnMgZnJvbSAxLg0KDQpgYGB7cn0NCnZfY29sb3JzWzJdICMgV2UgYXJlIHRyeWluZyB0byBleHRyYWN0IHRoZSBzZWNvbmQgZWxlbWVudCBvZiB0aGUgdmVjdG9yLCB2X2NvbG9ycw0Kdl9jb2xvcnNbYygxLDMpXSAgIyBXZSBjYW4gdXNlIHRoZSBjb25jYXRlbmF0aW9uIGZ1bmN0aW9uIHRvIGdldCBub25jb25zZWN1dGl2ZSBlbGVtZW50cy4gSGVyZSwgd2UgYXJlIHRyeWluZyB0byBleHRyYWN0IGVsZW1lbnRzIGluIHBvc2l0aW9ucyAxIGFuZCAzLg0KDQpgYGANCg0KSG93IHdvdWxkIHlvdXIgZXh0cmFjdCBlbGVtZW50cyAxOjksIDE1LCAxOSwgMjAgYW5kIDIxOjMwIGluIGB6emAgYmVsb3c/DQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMTIzNCkNCnp6IDwtIHJub3JtKDEwMCkNCmBgYA0KDQoqKkFuc3dlcjoqKg0KDQpgYGB7cn0NCnp6W2MoMToxOSwxNSwgMTksIDIwOjMwKV0NCmBgYA0KDQpXZSBjYW4gcmVwbGFjZSBlbGVtZW50cyBpbiBzcGVjaWZpYyBwb3NpdGlvbnMuIEJlbG93LCB3ZSByZXBsYWNlIHRoZSBzZWNvbmQgYW5kIHRoaXJkIGNvbG9ycyB3aXRoIGByZWRgIGFuZCBgcHVycGxlYC4NCg0KYGBge3J9DQoodl9jb2xvcnNbMjozXSAgPC0gYygicmVkIiwgInB1cnBsZSIpCSkNCmBgYA0KDQpTb21ldGltZXMgaXQgbWlnaHQgYmUgbW9yZSBjb252ZW5pZW50IHRvIGdldCByaWQgb2YgcGFydGljdWxhciBlbGVtZW50cyBpbnN0ZWFkLiBGb3IgZXhhbXBsZSwgSSBtaWdodCB3YW50IHRvIGV4dHJhY3QgYWxsICoqYnV0KiogdGhlIGZpcnN0IDUgZWxlbWVudHMgb2YgYSB2ZWN0b3IsIG9yIGFsbCBidXQgdGhlIDE1dGggZWxlbWVudC4gV2UgbWlnaHQgZmluZCBpdCBlYXNpZXIgdG8gdXNlIGEgbmVnYXRpdmUgaW5kZXggaGVyZS4NCg0KYGBge3J9DQpqIDwtIGMoLTEsLTIsLTMpDQp4W2pdDQoNCiMgV2UgY291bGQgaGF2ZSBkb25lIHRoYXQgaW4gb25lIGdvIGFzIHdlbGwNCnhbLWMoMTozKV0NCmBgYA0KDQojIyBDb25kaXRpb25hbCBzdWJzZXR0aW5nDQoNCkFub3RoZXIgY29tbW9uIHdheSB0byBzdWJzZXQgaXMgYnkgdXNpbmcgYSBsb2dpY2FsIHZlY3Rvci4gYFRSVUVgIHdpbGwgc2VsZWN0IHRoZSBlbGVtZW50IHdpdGggdGhlIHNhbWUgaW5kZXgsIHdoaWxlIGBGQUxTRWAgd2lsbCBub3QuIFR5cGljYWxseSwgdGhlc2UgbG9naWNhbCB2ZWN0b3JzIGFyZSBub3QgdHlwZWQgYnkgaGFuZCwgYnV0IGFyZSB0aGUgb3V0cHV0IG9mIG90aGVyIGZ1bmN0aW9ucyBvciBsb2dpY2FsIHRlc3RzIHN1Y2ggYXM6DQoNCmBgYHtyfQ0KeCA8LSAxMDA6MTEwDQp4DQoNCnggPjEwNSAjIHJldHVybnMgVFJVRSBvciBGQUxTRSBkZXBlbmRpbmcgb24gd2hpY2ggZWxlbWVudHMgdGhhdCBtZWV0IHRoZSBjb25kaXRpb24NCnNlbGVjdCA8LSB4ID4gMTA1DQp4W3NlbGVjdF0NCmBgYA0KSWYgd2Ugd291bGQgbGlrZSB0aGUgZWxlbWVudHMgdGhhdCBldmFsdWF0ZSB0byBgRkFMU0VgIGluc3RlYWQsIHdlIGNvdWxkIGVhc2lseSB1c2UgdGhlIGAhYCAoYE5PVGApIG9wZXJhdG9yDQoNCmBgYHtyfQ0KeFshc2VsZWN0XQ0KYGBgDQoNCi0tLQ0KDQpZb3UgY2FuIGNvbWJpbmUgbXVsdGlwbGUgdGVzdHMgdXNpbmc6DQoNCi0gYCZgIChgQU5EYCBvcGVyYXRvciAtIGJvdGggY29uZGl0aW9ucyBhcmUgdHJ1ZSkgb3INCg0KLSBgfGAgKGBPUmAgb3BlcmF0b3IgLSBfX2F0IGxlYXN0IG9uZV9fIG9mIHRoZSBjb25kaXRpb25zIGlzIHRydWUpDQoNCldlIGNhbiB0ZXN0IHdoZXRoZXIgeCBpcyBiZXR3ZWVuIHRoZSByYW5nZSAxMDMgYW5kIDEwNjoNCg0KYGBge3J9DQp4W3ggPj0gMTAzICYgeCA8PSAxMDZdDQpgYGANCg0KeCBpcyBncmVhdGVyIHRoYW4gMTAzIGJ1dCAoYEFORGApIGxlc3MgdGhhbiBvciBlcXVhbCB0byAxMDYNCg0KYGBge3J9DQp4W3ggPD0gMTA2ICYgeCA+IDEwM10gIyBvcmRlciBvZiBzdWJzZXR0aW5nIGRvZXMgbm90IG1hdHRlciBoZXJlIQ0KDQpgYGANCg0KeCBpcyBsZXNzIHRoYW4gMTAzIGBvcmAgZ3JlYXRlciB0aGFuIDEwNg0KYGBge3J9DQp4W3ggPj0gMTA2IHwgeCA8IDEwM10NCg0KYGBgDQoNCi0tLQ0KDQpTb21ldGltZXMgd2Ugd2lsbCBuZWVkIHRvIHNlYXJjaCBmb3IgY2VydGFpbiBzdHJpbmdzIGluIGEgdmVjdG9yLiBXaXRoIG11bHRpcGxlIGNvbmRpdGlvbnMsIGl0IGJlY29tZXMgZGlmZmljdWx0IHRvIHVzZSB0aGUgIk9SIiBvcGVyYXRvciBgfGAuIFRoZSBmdW5jdGlvbiBgJWluJWAgYWxsb3dzIHlvdSB0byB0ZXN0IGlmIGFueSBvZiB0aGUgZWxlbWVudHMgb2YgYSBzZWFyY2ggdmVjdG9yIGFyZSBmb3VuZDoNCg0KYGBge3J9DQphbmltYWxzIDwtIGMoIm1vdXNlIiwgInJhdCIsICJkb2ciLCAiY2F0IikNCmFuaW1hbHNbYW5pbWFscyA9PSAiY2F0IiB8IGFuaW1hbHMgPT0gInJhdCJdICMgcmV0dXJucyBib3RoIHJhdCBhbmQgY2F0DQoNCmFuaW1hbHMgJWluJSBjKCJyYXQiLCAiY2F0IiwgImRvZyIsICJkdWNrIiwgImdvYXQiKQ0KYW5pbWFsc1thbmltYWxzICVpbiUgYygicmF0IiwgImNhdCIsICJkb2ciLCAiZHVjayIsICJnb2F0IildDQpgYGANCg0KDQojIyBOYW1lcyBvZiBhIHZlY3Rvcg0KDQpMZXQncyBzYXkgdGhhdCB3ZSB3YW50IHRvIGtub3cgd2hpY2ggY29sb3Igcm9iZSBlYWNoIG9mIDMgcGF0aWVudHMgaXMgd2VhcmluZywgd2UgY2FuIGFzc2lnbiBuYW1lcyB0byB0aGUgdmVjdG9yIG9mIGNvbG9ycy4NCmBgYHtyLCBlY2hvPVRSVUV9DQp2X2NvbG9ycw0KbmFtZXModl9jb2xvcnMpIDwtIGMoIlRob21hcyIsICJMaXoiLCAiVHVja2VyIikNCnZfY29sb3JzDQpgYGANCg0KIyMgQWxnZWJyYWljIE9wZXJhdGlvbnMgb2YgVmVjdG9ycw0KDQpgYGB7ciwgZWNobz1UUlVFfQ0KeCA8LSBjKDEsMiwzKQ0KeSA8LSBjKDQsNSw2KQ0KIyBjb21wb25lbnQtd2lzZSBhZGRpdGlvbg0KeCt5DQojIGNvbXBvbmVudC13aXNlIG11bHRpcGxpY2F0aW9uDQp4KnkNCiMgV2hhdCBoYXBwZW5zIHRvIHRoZSBmb2xsb3dpbmcNCnleeCAjIG9yIHkqKngNCmBgYA0KDQoNCiMjIFJlcGVhdGluZyBWZWN0b3IgaW4gYFJgDQoNCmBgYHtyLCB3YXJuaW5nPVRSVUUsIGVjaG89VFJVRX0NCiMgV291bGQgdGhpcyB3b3JrPw0KYygxLDIsMyw0KSArIGMoMSwyKQ0KIyBXb3VsZCB0aGlzIHdvcms/DQpjKDEsMiwzKSArIGMoMSwyKQ0KYGBgDQoNCipXaHkgdGhlIHdlaXJkIHJlc3VsdHM/Kg0KDQotIFdoZW4geW91IGFyZSBhZGRpbmcgdmVjdG9ycyBvZiB1bmVxdWFsIHNpemUsIGlmIHRoZSBsb25nIG9uZSBpcyBhIG11bHRpcGxlIG9mIHRoZSBzaG9ydCBvbmUsIGBSYCBhdXRvbWF0aWNhbGx5IHJlcGVhdHMgdGhlIHNob3J0IG9uZSB0byBmaWxsIGluIHRoZSBvcGVyYXRpb24uDQoNCmBgYHtyLCBlY2hvID0gVFJVRX0NCjIqYygxLDIsMykNCmBgYA0KDQojIyBNYXRyaXgNCg0KKipDcmVhdGUgYSBuZXcgbWF0cml4KioNCmBgYHtyfQ0KKG1hdHJpeDwtbWF0cml4KDE6MTYsIG5yb3cgPSA0LCBieXJvdyA9IFRSVUUpKQ0KYGBgDQoNCk5vdGUgdGhhdCBgOmAgbWVhbnMgZXZlcnkgbnVtYmVyIGZyb20gMSB0byA0LiBJbiB0aGUgYG1hdHJpeCgpYCBmdW5jdGlvbjoNCg0KMS4gVGhlIGZpcnN0IGFyZ3VtZW50IGlzIHRoZSBjb2xsZWN0aW9uIG9mIGVsZW1lbnRzIHRoYXQgYFJgIHdpbGwgYXJyYW5nZSBpbnRvIHRoZSByb3dzIGFuZCBjb2x1bW5zIG9mIHRoZSBtYXRyaXguIEhlcmUsIHdlIHVzZSAxOjE2IHdoaWNoIGlzIGEgc2hvcnRjdXQgZm9yIGMoMSwgMiwgMywgNCwgLi4uIDE2KS4NCjIuIFRoZSBhcmd1bWVudCBgYnlyb3dgIGluZGljYXRlcyB0aGF0IHRoZSBtYXRyaXggaXMgZmlsbGVkIGJ5IHRoZSByb3dzLiBJZiB3ZSB3YW50IHRoZSBtYXRyaXggdG8gYmUgZmlsbGVkIGJ5IHRoZSBjb2x1bW5zLCB3ZSB1c2UgYGJ5cm93ID0gRkFMU0VgLg0KMy4gVGhlIGFyZ3VtZW50IGBucm93YCBpbmRpY2F0ZXMgdGhhdCB0aGUgbWF0cml4IHNob3VsZCBoYXZlIDQgcm93cy4NCg0KIyMgU2VsZWN0aW9uIG9mIE1hdHJpeCBFbGVtZW50cw0KU2VsZWN0aW9uIG9mIHRoZSBtYXRyaXggZWxlbWVudHMgYXJlIHNpbWlsYXIgdG8gdmVjdG9ycyBleGNlcHQgd2UgaGF2ZSB0d28gZGltZW5zaW9ucyBvdmVyIHdoaWNoIHRvIHN1YnNldC0gcm93cyBhbmQgY29sdW1ucy4NCg0KYGBge3J9DQoNCiMgbWF0cml4W3IsY10gI1N0YW5kYXJkIGZvcm0gb2YgdGhlIG1hdHJpeC4NCg0KbWF0cml4WzEsMl0gI0V4dHJhY3QgZWxlbWVudCBpbiB0aGUgZmlyc3Qgcm93IGFuZCBzZWNvbmQgY29sdW1uDQojRXh0cmFjdCB0aGUgZW50aXJlIGZpcnN0IHJvdyBhbmQgc2Vjb25kIGNvbHVtbnMNCm1hdHJpeFssMToyXQ0KYGBgDQoNCg0KIyMgQXNzaWduIGRpbWVuc2lvbiBuYW1lcyB0byBNYXRyaXgNCg0KYGBge3J9DQoJcm93bmFtZXMobWF0cml4KSA8LSBjKCJZZXMiLCAiTm8iLCAiUGVyaGFwcyIsICJNYXliZSIpDQoJY29sbmFtZXMobWF0cml4KSA8LSBjKCJBcHBsZSIsICJQZWFyIiwgIkJhbmFuYSIsICJHcmFwZXMiKQ0KCW1hdHJpeA0KYGBgDQoNCiMjIERpbWVuc2lvbiBvZiBhIG1hdHJpeCB2cyB2ZWN0b3INCg0KYGBge3J9DQp4IDwtIGMoMSwyLDMpDQptYXRyaXg8LW1hdHJpeCgxOjQsIGJ5cm93ID0gVFJVRSwgbnJvdyA9IDIpDQpsZW5ndGgoeCkNCmxlbmd0aChtYXRyaXgpDQpkaW0obWF0cml4KQ0KZGltKHgpDQpgYGANCg0KDQojIyBMaXN0cw0KDQpgUmAgZG9lc27igJl0IGxpa2UgdmVjdG9ycyB0byBoYXZlIGRpZmZlcmVudCB0eXBlczogYGMoVFJVRSwgMSwgIkZyYW5rIilgIGJlY29tZXMgYGMoIlRSVUUiLCAiMSIsICJGcmFuayIpYC4gQnV0IHN0b3Jpbmcgb2JqZWN0cyB3aXRoIGRpZmZlcmVudCB0eXBlcyBpcyBhYnNvbHV0ZWx5IGZ1bmRhbWVudGFsIHRvIGRhdGEgYW5hbHlzaXMuIGBSYCBoYXMgYSBkaWZmZXJlbnQgdHlwZSBvZiBvYmplY3QgYmVzaWRlcyBhIHZlY3RvciB1c2VkIHRvIHN0b3JlIGRhdGEgb2YgZGlmZmVyZW50IHR5cGVzIHNpZGUtYnktc2lkZTogYSBsaXN0Og0KDQpgYGB7cn0NCmMoVFJVRSwgMSwgIkZyYW5rIikNCnggPC0gbGlzdChUUlVFLCAxLCAiRnJhbmsiKQ0KeA0KYGBgDQoNCk1hbnkgZGlmZmVyZW50IHRoaW5ncyBub3QgbmVjZXNzYXJpbHkgb2Ygc2FtZSBsZW5ndGggY2FuIGJlIHB1dCB0b2dldGhlci4NCg0KYGBge3J9DQp4IDwtIGxpc3QoYygxOjUpLCBjKCJhIiwgImIiLCJjIiksIGMoVFJVRSwgRkFMU0UpLCBjKDVMLCA2TCkpDQp4DQpgYGANCg0KDQojIyBEYXRhZnJhbWVzDQoNCi0gRGF0YSBmcmFtZXMgYXJlIGxpa2Ugc3ByZWFkc2hlZXQgZGF0YSwgcmVjdGFuZ3VsYXIgd2l0aCByb3dzIGFuZCBjb2x1bW5zLg0KLSBJZGVhbGx5IGVhY2ggcm93IHJlcHJlc2VudHMgZGF0YSBvbiBhIHNpbmdsZSBvYnNlcnZhdGlvbiBhbmQgZWFjaCBjb2x1bW4gY29udGFpbnMgZGF0YSBvbiBhIHNpbmdsZSB2YXJpYWJsZSwgb3IgY2hhcmFjdGVyaXN0aWMsIG9mIHRoZSBvYnNlcnZhdGlvbi4NCi0gSXQgcmVwcmVzZW50cyB0aGUgZGF0YSBpbiAgYSB0YWJ1bGFyIGZvcm1hdCB3aGVyZSB0aGUgY29sdW1ucyBhcmUgdmVjdG9ycyB0aGF0IGFsbCBoYXZlIHRoZSBzYW1lIGxlbmd0aC4gQmVjYXVzZSBjb2x1bW5zIGFyZSB2ZWN0b3JzLCBlYWNoIGNvbHVtbiBtdXN0IGNvbnRhaW4gYSBzaW5nbGUgdHlwZSBvZiBkYXRhIChlLmcuLCBjaGFyYWN0ZXJzLCBpbnRlZ2VycywgZmFjdG9ycykuDQotIFdlIGNhbiBvcGVuIGEgZGF0YSB2aWV3ZXIgd2luZG93IHRvIHNlZSB0aGUgY29udGVudHMgb2YgYFJgJ3MgYGlyaXNgIGRhdGEgZnJhbWUgYnkgdHlwaW5nLg0KLSBXZSB3aWxsIGJlIHdvcmtpbmcgd2l0aCBzcHJlYWRzaGVldHMgYSBsb3QuDQoNCmBgYHtyLCBldmFsPUZBTFNFLCBlY2hvPVRSVUV9DQpWaWV3KGlyaXMpDQpgYGANCg0KDQojIyBDcmVhdGUgYSBkYXRhIGZyYW1lDQoNCkRhdGEgZnJhbWUgd2l0aCBIYXJyeSBQb3R0ZXIgY2hhcmFjdGVycw0KDQpgYGB7cn0NCm5hbWUgPC0gYygiSGFycnkiLCAiUm9uIiwgIkhlcm1pb25lIiwgIkhhZ3JpZCIsICJWb2xkZW1vcnQiKQ0KaGVpZ2h0IDwtIGMoMTc2LCAxNzUsIDE2NywgMjMwLCAxODApDQpncGEgPC0gYygzLjQsIDIuOCwgNC4wLCAyLjIsIDMuNCkNCmRmX3N0dWRlbnRzIDwtIGRhdGEuZnJhbWUobmFtZSwgaGVpZ2h0LCBncGEpDQpkZl9zdHVkZW50cw0KYGBgDQoNCi0tLQ0KDQpBbHRlcm5hdGl2ZSB3YXkgb2YgY3JlYXRpbmcgREYNCg0KYGBge3J9DQoJZGZfc3R1ZGVudHMgPC0gZGF0YS5mcmFtZShuYW1lID0gYygiSGFycnkiLCAiUm9uIiwgIkhlcm1pb25lIiwgIkhhZ3JpZCIsICJWb2xkZW1vcnQiKSwNCgkJCQkgIGhlaWdodCA9IGMoMTc2LCAxNzUsIDE2NywgMjMwLCAxODApLA0KCQkJCSAgZ3BhID0gYygzLjQsIDIuOCwgNC4wLCAyLjIsIDMuNCkpDQoJZGZfc3R1ZGVudHMNCmBgYA0KDQoNCiMjIEFkZGluZyB2YXJpYWJsZQ0KDQpgYGB7ciwgZWNobyA9IFRSVUV9DQoJZGZfc3R1ZGVudHMkZ29vZCA8LSBjKDEsIDEsIDEsIDEsIDApDQoJZGZfc3R1ZGVudHMNCmBgYA0KDQoNCiMjIEZlYXR1cmVzIG9mIHRoZSBERg0KDQpgYGB7ciwgZXZhbD1GQUxTRSwgZWNobz1UUlVFfQ0KCWRpbShkZl9zdHVkZW50cykNCglkZl9zdHVkZW50c1syLCAzXSAgICAgICAgICAgICAgICNSb24ncyBHUEENCglkZl9zdHVkZW50cyRncGFbMl0gICAgICAgICAgICAgICNSb24ncyBHUEENCglkZl9zdHVkZW50c1s1LCBdICAgICAgICAgICAgICAgICNnZXQgcm93IDUNCglkZl9zdHVkZW50c1szOjUsIF0gICAgICAgICAgICAgICNnZXQgcm93cyAzLTUNCglkZl9zdHVkZW50c1ssIDJdICAgICAgICAgICAgICAgICNnZXQgY29sdW1uIDIgKGhlaWdodCkNCglkZl9zdHVkZW50cyRoZWlnaHQgICAgICAgICAgICAgICNnZXQgY29sdW1uIDIgKGhlaWdodCkNCglkZl9zdHVkZW50c1ssIDE6M10gICAgICAgICAgICAgICNnZXQgY29sdW1ucyAxLTMNCglkZl9zdHVkZW50c1s0LCAyXSA8LSAyNTUgICAgICAgICNyZWFzc2lnbiBIYWdyaWQncyBoZWlnaHQNCglkZl9zdHVkZW50cyRoZWlnaHRbNF0gPC0gMjU1ICAgICNzYW1lIHRoaW5nIGFzIGFib3ZlDQoJZGZfc3R1ZGVudHMNCmBgYA0KDQoNCiMjIEV4ZXJjaXNlDQoNCk5vdyB0aGF0IHlvdSBhcmUgZXF1aXBwZWQgd2l0aCB0aGUgYmFzaWMsIGdvIGFoZWFkIGFuZCB0YWtlIHRoZSBmb2xsb3dpbmcgRGF0YWNhbXAgQ291cnNlLCBbUiBJbnRybyBvbiBEYXRhY2FtcF0oaHR0cHM6Ly9jYW1wdXMuZGF0YWNhbXAuY29tL2NvdXJzZXMvZnJlZS1pbnRyb2R1Y3Rpb24tdG8tcikuIFlvdXIgaW52aXRhdGlvbnMgc2hvdWxkIG5vdyBiZSBpbiB5b3VyIGluYm94Lg0KDQoNCiMgUGFydCBJVjogV29ya2luZyBkaXJlY3Rvcmllcw0KDQpZb3UgY2FuIHVzZSB0aGUNCmBgYHtyLCBldmFsID0gRkFMU0UsIGVjaG89VFJVRX0NCmdldHdkKCkNCmBgYA0KY29tbWFuZCB0byBvYnRhaW4gdGhlIGN1cnJlbnQgZGlyZWN0b3J5IGBSYCBpcyB1c2luZy4NCg0KSXQgaXMgZ29vZCBwcmFjdGljZSB0byBzZXQgdGhlIHdvcmtpbmcgZGlyZWN0b3J5IGxvY2F0aW9uIHRvIHdoZXJlIHRoZSBmaWxlcyBhbmQgZGF0YSBhcmUgc3RvcmVkLg0KDQotIENvbnNpZGVyIHNldHRpbmcgeW91ciB3b3JraW5nIGRpcmVjdG9yeSB0byBhIGZvbGRlciBjYWxsZWQgQUFFQzQ5ODQsIEFBRUM1NDg0LCBvciBTVEFUNTQ4NCBvbiB5b3VyIGRlc2t0b3AgKGZvciBleGFtcGxlKS4NCg0KIyMgQ3JlYXRpbmcgRGlyZWN0b3J5IGFuZCBTZXQgd29ya2luZyBkaXJlY3RvcnkNCg0KKipXaW5kb3dzKioNCmBgYHtyLCBldmFsID0gRkFMU0UsIGVjaG89VFJVRX0NCiAgc2V0d2QoIkM6L3VzZXJzL1t5b3VyIHVzZXIgbmFtZV0vRGVza3RvcC9BQUVDNDk4NC8iKQ0KICAjIE9SDQogIHNldHdkKCJDOlxcdXNlcnNcXFt5b3VyIHVzZXIgbmFtZV1cXERlc2t0b3BcXEFBRUM0OTg0XFwiKQ0KICAjIG5vdGljZSB0aGUgZG91YmxlIGJhY2tzbGFzaGVzDQpgYGANCg0KKipNYWMqKg0KYGBge3IsIGV2YWwgPSBGQUxTRSwgZWNobz1UUlVFfQ0KICBzZXR3ZCgifi9EZXNrdG9wL0FBRUM0OTg0IikNCmBgYA0KDQotIFRvIGNoZWNrIHdoZXRoZXIgdGhlIHdkIGlzIGNvcnJlY3QsIHdlIGFnYWluIHVzZQ0KDQpgYGB7ciwgZXZhbCA9IEZBTFNFLCBlY2hvPVRSVUV9DQpnZXR3ZCgpDQpgYGANCg0KLSBUbyBvYnRhaW4gYSBsaXN0IG9mIHRoZSBuYW1lcyBvZiBmaWxlcyBvciBmb2xkZXJzIGluIHRoZSB3b3JraW5nIGRpcmVjdG9yeSwgd2UgY2FuIHVzZQ0KDQpgYGB7ciwgZXZhbCA9IEZBTFNFLCBlY2hvPVRSVUV9DQpkaXIoKQ0KYGBgDQoNCi0gVG8gY3JlYXRlIGEgbmV3IGZvbGRlciBpbiB5b3VyIGRpcmVjdG9yeSB3ZSBjYW4gdXNlDQpgYGB7ciwgZXZhbCA9IEZBTFNFfQ0KZGlyLmNyZWF0ZSgiW0ZvbGRlciBuYW1lXSIpDQpgYGANCg0KIyMgSW1wb3J0aW5nIGRhdGENCg0KYFJgIGFsbG93cyB1cyB0byBpbXBvcnQgc2V2ZXJhbCBmaWxlIHR5cGVzLiBJIHdpbGwgZGlzY3VzcyAzIHRoYXQgd2UgYXJlIG1vc3QgbGlrZWx5IHRvIHVzZSBpbiB0aGlzIGNvdXJzZS4NCg0KMS4gVGV4dCBmaWxlcw0KOiBEYXRhIHNvbWV0aW1lcyBjb21lIHdpdGggaGVhZGVycyAodGhlIGZpcnN0IHJvdyBpcyB2YXJpYWJsZSBuYW1lcywgbm90IGFjdHVhbCBkYXRhISkgWW91IG5lZWQgdG8gdGVsbCBSIHRoYXQhDQoNCmBgYHtyLCBldmFsPSBGQUxTRSwgZWNobz1UUlVFfQ0KdGV4dGRhdGE8LXJlYWQudGFibGUoImV4YW1wbGVzL2hvZ3NkYXRhLnR4dCIsaGVhZGVyPVQpDQpgYGANCg0KMi4gQ1NWIGZpbGVzDQo6DQpgYGB7cixldmFsPUZBTFNFLCBlY2hvID0gRkFMU0V9DQpjc3ZkYXRhIDwtIHJlYWQuY3N2KCJleGFtcGxlcy9ob2dzZGF0YS5jc3YiLGhlYWRlcj1UKQ0KYGBgDQoNCjMuIHhsc3ggZmlsZXMgKHJlcXVpcmVzIG9wZW54bHN4IHBhY2thZ2UpDQpgYGB7ciwgZXZhbD0gRkFMU0UsIGVjaG89VFJVRX0NCnhsc3hkYXRhIDwtIHJlYWQuY3N2KCJleGFtcGxlcy9ob2dzZGF0YS54bHN4IiwgLi4uICkNCmBgYA0KDQoNCiMjIEZ1bmN0aW9ucyAmIFBhY2thZ2VzDQoNCkZ1bmN0aW9ucyBhcmUg4oCcY2FubmVkIHNjcmlwdHPigJ0gdGhhdCBhdXRvbWF0ZSBtb3JlIGNvbXBsaWNhdGVkIHNldHMgb2YgY29tbWFuZHMgaW5jbHVkaW5nIG9wZXJhdGlvbnMgYXNzaWdubWVudHMsIGV0Yy4gRm9yIHRoZSBwdXJwb3NlIG9mIHRoaXMgY291cnNlLCB3ZSB3aWxsIHVzZSBhIGxvdCBvZiBmdW5jdGlvbnMgdGhhdCBhcmUgYnVpbHQgYm90aCBpbiBiYXNlIFIgKHRoYXQgaXMsIHRoZXkgYXJlIHByZWRmaW5lZCkgb3IgYXZhaWxhYmxlIHRocm91Z2ggUiBwYWNrYWdlcyAoZGlzY3VzcyBiZWxvdykuDQoNCkEgZnVuY3Rpb24gdXN1YWxseSB0YWtlcyBvbmUgb3IgbW9yZSBpbnB1dHMgY2FsbGVkICphcmd1bWVudHMqLCBhbmQgb2Z0ZW4gKGJ1dCBub3QgYWx3YXlzKSByZXR1cm4gYSAqdmFsdWUqLg0KDQotLS0NCg0KQ29uc2lkZXIgZm9yIGV4YW1wbGUsIHRha2luZyB0aGUgYXZlcmFnZSBvZiBhIHNldCBvZiByYW5kb20gbnVtYmVycyAoeCkuDQoNCmBgYHtyLCByZXN1bHRzPSdtYXJrdXAnLCBlY2hvPVRSVUV9DQpzZXQuc2VlZCgxMjQpDQp4IDwtIHJub3JtKDYpICogMTAwDQoocm91bmQoeCwgZGlnaXRzPTIpKSAjIHJvdW5kIGZ1bmN0aW9uID0+IDJkcA0KYGBgDQoNCklmIHdlIHdlcmUgdG8gZG8gdGhpcyBtYW51YWxseSwgd2Ugd291bGQ6DQoNCjEuIFN1bSB1cCB0aGUgdmFsdWVzDQpgYGB7ciwgZWNobz1UUlVFfQ0Kc3VteCA8LSBzdW0oeCkNCmBgYA0KDQoyLiBHZXQgdGhlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMNCmBgYHtyLCBlY2hvPVRSVUV9DQpueCA8LSBsZW5ndGgoeCkNCmBgYA0KDQozLiBEaXZpZGUgc3VtIGJ5IHRvdGFsIG51bWJlciBvZiBvYnNlcnZhdGlvbnMNCg0KYGBge3IsIGVjaG89VFJVRX0NCm1lYW54IDwtIHN1bXgvbngNCmBgYA0KDQpVc2luZyBgUmAncyBidWlsdCBpbiBgbWVhbmAgZnVuY3Rpb24gd2UgY2FuIGRvIGFsbCB0aHJlZSBzdGVwcyBpbnRlcm5hbGx5IGFuZCBjcm9zcyBjaGVjayBhZ2FpbnN0IG91ciBtYW51YWwgY2FsY3VsYXRpb25zLg0KDQpgYGB7ciwgZWNobz1UUlVFfQ0KbWVhbih4KQ0KbWVhbnggPT0gbWVhbih4KSAjIGNyb3NzIHZhbGlkYXRpb24NCmBgYA0KDQojIyBJbnN0YWxsaW5nIFBhY2thZ2VzDQoNClNpbmNlIGBSYCBpcyBhbiBPcGVuIFNvdXJjZSBzb2Z0d2FyZSBwcm9ncmFtLCB0aG91c2FuZHMgb2YgcGVvcGxlIGNvbnRyaWJ1dGUgdG8gdGhlIHNvZnR3YXJlLiBUaGV5IGRvIHRoaXMgYnkgd3JpdGluZyBjb21tYW5kcyAoY2FsbGVkIGZ1bmN0aW9ucykgdG8gbWFrZSBhIHBhcnRpY3VsYXIgYW5hbHlzaXMgZWFzaWVyLCBvciB0byBtYWtlIGEgZ3JhcGhpYyBwcmV0dGllci4NCg0KV2hlbiB5b3UgZG93bmxvYWQgYFJgLCB5b3UgZ2V0IGFjY2VzcyB0byBhIGxvdCBvZiBmdW5jdGlvbnMgdGhhdCB3ZSB3aWxsIHVzZS4gSG93ZXZlciB0aGUgb3RoZXIgdXNlci13cml0dGVuIHBhY2thZ2VzIHdlIHVzZSBmb3Igb3VyIGFuYWx5c2VzIHdpbGwgbWFrZSBvdXIgbGl2ZXMgbXVjaCBlYXNpZXIuDQoNCkZvciBleGFtcGxlLCB0aG91Z2ggd2UgY2FuIHVzZSB0aGUgYHBsb3RgIGNvbW1hbmQgZm9yIHN0YW5kYXJkIGdyYXBoaWNzLCB5b3Ugd2lsbCBxdWlja2x5IHNlZSB0aGF0IHdlIGNhbiBnZXQgbXVjaCBiZXR0ZXIgbG9va2luZyB0aW1lIHNlcmllcyBncmFwaHMgdXNpbmcgdGhlIGBmcHAzYCBwYWNrYWdlICh3aGljaCBhbHNvIHVzZXMsIGFtb25nIG90aGVyIHBhY2thZ2VzLGBnZ3Bsb3QyYCkuDQoNCg0KIyMgSW5zdGFsbGluZyBQYWNrYWdlcw0KDQpUbyBpbnN0YWxsIHRoZSBgZnBwMmAgcGFja2FnZSwgd2UgY2FuIHVzZSB0aGUgY29tbWFuZA0KYGBge3IsIGV2YWw9RkFMU0UsIGVjaG89VFJVRX0NCmluc3RhbGwucGFja2FnZXMoImZwcDMiKQ0KYGBgDQpXZSB3aWxsIG5lZWQgdG8gaW5zdGFsbCBhIHBhY2thZ2Ugb25seSBvbmNlIGluIGBSYC4NCg0KTm93IHRoYXQgeW91IGhhdmUgdGhlIGBmcHAzYCBwYWNrYWdlIGluc3RhbGxlZCwgd2UgY2FuIGNoZWNrIHRvIHNlZSBpZiBpdCBpcyBpbiB1c2UNCmBgYHtyIGV2YWw9RkFMU0UsIGVjaG89VFJVRX0NCnNlYXJjaCgpDQpgYGANCg0KTGFzdGx5LCBpbiBvcmRlciB0byB1c2UgdGhlIHBhY2thZ2UsIHdlIHdpbGwgbmVlZCB0byBsb2FkIHRoZSBsaWJyYXJ5DQpgYGB7ciBldmFsPVRSVUUsIG1lc3NhZ2U9IEZBTFNFLCBlY2hvPVRSVUV9DQpsaWJyYXJ5KGZwcDMpDQpgYGANCg0KIyMgVXNpbmcgbGlicmFyaWVzDQoNClRoZSBgZnBwM2AgcGFja2FnZSBjb250YWlucyBhIG51bWJlciBvZiB1c2VmdWwgZGF0YXNldHMuIE9uZSBzdWNoIGRhdGEgc2V0IGlzIGB1c19nYXNvbGluZWAgKFdlZWtseSBVUyBmaW5pc2hlZCBtb3RvciBnYXNvbGluZSBwcm9kdWN0IHN1cHBsaWVkKS4NCg0KVXNlIHRoZSBgaGVscCgpYCBmdW5jdGlvbiB0byBnZXQgYSBkZXNjcmlwdGlvbiBvZiB0aGlzIGRhdGEuIFRyeQ0KYGBge3IsZXZhbD0gVFJVRSwgZWNobz1UUlVFfQ0KaGVscCh1c19nYXNvbGluZSkNCmBgYA0KDQpOb3cgbGV0IHVzIGNyZWF0ZSBhIG5pY2UgcGxvdCBvZiB0aGUgYHVzX2dhc29saW5lYCBkYXRhLiANCg0KYGBge3IgLCBmaWcuaGVpZ2h0PSAyLjUsIGVjaG89VFJVRX0NCmF1dG9wbG90KHVzX2dhc29saW5lLCBjb2wgPSAiZGFya2dyZWVuIikgKw0KICAjTm93IHRvIGFkZCBheGlzIGxhYmVscw0KICBsYWJzKHRpdGxlID0gIldlZWtseSBVUyBmaW5pc2hlZCBtb3RvciBnYXNvbGluZSBwcm9kdWN0IHN1cHBsaWVkIiwNCiAgICAgICB5ID0gIk1iZCIsIGNhcHRpb24gPSAiU291cmNlOiBmcHAzIHBhY2thZ2UiKSArIA0KICB0aGVtZV9saWdodCgpICMgT25lIG9mIG1hbnkgdGhlbWVzIGluIFINCmBgYA0KDQotLS0NCg0KTGV0IHVzIGxlYXZlIGl0IHRoZXJlIGZvciBub3chDQoNCi0tLQ0KDQoNCg0KDQo=
2.1 Comments
Whenever possible, use comments! Anything following the symbol
#in an R Script will not be run in R.Comments are notes we leave ourselves so we know:
I promise that this will become useful when you come back to your code after an extended time. I cannot tell you the number of times I have had a moment of pure genius while coding and I spend hours on a different day trying to understand why I coded it like that or what I actually did.
For example, below is the type of comments that I always include in my programs
You can also understand the following code without even knowing what exactly each line of command does because I tell you what they are!